package com.topnav.mc.zzd;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.js.lib.result.Result;
import com.topnav.mc.admin.security.PermissionGrade;
import com.topnav.mc.uitls.RedisUtil;
import com.topnav.mc.zzd.account.ZzdAccount;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Map;

/**
 * 卓智达API调用工具类
 * @Author: kenny
 * @Date: 2024/1/9 10:46
 */
@Slf4j
public class ZzdHttpUtil {
    /**
     * 发起请求
     * @param url
     * @param successCallBack
     * @param failedCallBack
     */

    /**
     *
     * @param url
     * @param paramsMap
     * @param zzdAccount 这里保存有登录信息
     * @param successCallBack
     * @param failedCallBack
     */
    public static void request(String url, Map<String, String> paramsMap, ZzdAccount zzdAccount, ApiCallBack successCallBack, ApiCallBack failedCallBack) {
        System.out.println("request:url:"+url);

        //请求地址带上SessionId
        String sessionId = (String)RedisUtil.get(ZzdConstant.ZZD_SESSIONID_PREFIX + zzdAccount.getAccount());
        if(sessionId!=null){
            url=url.replace(";jsessionid=", ";jsessionid="+sessionId);
        }
        String finalUrl=url;
        //发起请求
        String result=requestHttp(url, "POST", paramsMap, null, 0);
        //System.out.println("request:result:"+result);

        if(result!=null) {
            JSONObject resultObj=JSONObject.parseObject(result);

            int code=resultObj.getIntValue("code");
            //System.out.println("request:code:"+code);

            //未登录时：{"code":1001,"data":{},"msg":"notLoggedIn"}
            if(code==1001){//未登录
                //先登录
                login(zzdAccount,new ApiCallBack() {

                    @Override
                    public void onResult(String result) {
                        //登录成功，重新发起请求
                        //request(finalUrl, paramsMap,successCallBack, failedCallBack);
                        //登录成功，查询有效订单，再重新发起请求
                        queryOrders(finalUrl, paramsMap,zzdAccount,successCallBack, failedCallBack);
                    }
                },failedCallBack);
            }else if(code==0){//成功
                successCallBack.onResult(result);
            }else{//其他错误
                failedCallBack.onResult(result);
            }
        }
    }

    /**
     * 发送http请求
     * @param serverUrl
     * @param requestMethod
     * @param paramsMap
     * @param data
     * @param length
     * @return
     */
    private static String requestHttp(String serverUrl, String requestMethod, Map<String, String> paramsMap, byte[] data, int length){
        HttpURLConnection connection=null;
        try {
            connection = (HttpURLConnection)getConnection(serverUrl, requestMethod, paramsMap);
            if(length > 0){
                connection.setRequestProperty("Content-Length", String.valueOf(length));
            }
            connection.connect();

            if(length > 0){
                OutputStream os = connection.getOutputStream();
                os.write(data, 0, length);
                os.flush();
                os.close();
            }

            if (connection.getResponseCode() == 200) {
                InputStream is = connection.getInputStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                int len = 0;
                byte buffer[] = new byte[1024];
                while ((len = is.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                is.close();
                baos.close();
                String result = new String(baos.toByteArray(),"utf-8");
                return result;
            } else {//其他错误码
                System.out.println(String.format("err: %s,code:%s",serverUrl,connection.getResponseCode()));
                JSONObject resultObj=new JSONObject();
                resultObj.put("code",connection.getResponseCode());
                resultObj.put("msg",connection.getResponseCode()+"错误！");
                return resultObj.toString();
            }
        } catch (Exception e) {//连接错误
            e.printStackTrace();
        } finally {
            if(connection!=null) {
                connection.disconnect();
            }
        }
        return null;
    }
    /**
     * 获取http连接对象
     * @param serverUrl
     * @param requestMethod
     * @param paramsMap
     * @return
     */
    private static URLConnection getConnection(String serverUrl, String requestMethod, Map<String, String> paramsMap) {
        HttpURLConnection connection = null;
        try {
            //String url1 = URLEncoder.encode(serverUrl);
            URL url = new URL(serverUrl);
            //System.out.println(url);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod(requestMethod);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setReadTimeout(5000);
            connection.setConnectTimeout(5000);
            connection.setRequestProperty("contentType", "UTF-8");
            connection.setRequestProperty("Connection", "close");
            connection.setRequestProperty("Response-Type", "json");
            if(paramsMap != null) {
                for (String key : paramsMap.keySet()) {
                    try {
                        if(paramsMap.get(key) != null){
                            connection.setRequestProperty(key, paramsMap.get(key));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
        }
        return connection;
    }

    /**
     * 登录
     * @param successCallBack
     * @param failedCallBack
     */
    private static void login(ZzdAccount zzdAccount,ApiCallBack successCallBack, ApiCallBack failedCallBack) {
        System.out.println("login");
        //先获取随机数
        request("https://smart-ptt.com/ptt/random",null,zzdAccount,new ApiCallBack() {
            @Override
            public void onResult(String result) {
                //获取随机数成功
                //解析随机数
                JSONObject object = JSONObject.parseObject(result);
                String random = object.getJSONObject("data").getString("random");
                String sessionId = object.getJSONObject("data").getString("sessionId");
                System.out.println("login:random:" + random);
                System.out.println("login:sessionId:" + sessionId);

                if (RedisUtil.set(ZzdConstant.ZZD_SESSIONID_PREFIX + zzdAccount.getAccount(), sessionId,ZzdConstant.ZZD_SESSION_VALIDIDTY)
                    && RedisUtil.set(ZzdConstant.ZZD_RANDOM_KEY,random,ZzdConstant.ZZD_SESSION_VALIDIDTY)
                ) {
                    ;
                    //计算密码
                    String sha1Password = sha1(zzdAccount.getPassword());
                    System.out.println("login:sha1Password:" + sha1Password);
                    String hmacSha1Password = hmacSha1(random, sha1Password);
                    System.out.println("login:hmacSha1Password:" + hmacSha1Password);
                    //正式登录
                    //String static account = permissionGrade.getD3PartAcount().get("account");
                    request("https://smart-ptt.com/ptt/organization;jsessionid=?method=login"
                                    + "&account="  + zzdAccount.getAccount()
                                    + "&pwd=" + hmacSha1Password
                                    + "&timeZoneOffset=-480",
                            null,
                            zzdAccount,
                            successCallBack, failedCallBack);

                }else{
                    log.error(">>>>>> 写入redis错误！");
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("code",-1000);
                    jsonObject.put("msg","写入redis错误");
                    failedCallBack.onResult(jsonObject.toString());
                }
            }
        },failedCallBack);
    }

    /**
     * 查询有效订单并保存至redis
     */
    private static void queryOrders(String finalUrl,Map<String, String> paramsMap,ZzdAccount zzdAccount,ApiCallBack successCallBack,ApiCallBack failedCallBack) {
        request("https://smart-ptt.com/ptt/bill;jsessionid=?method=get&limit=100&page=0&status=1", null,zzdAccount,
                new ApiCallBack() {
                    @Override
                    public void onResult(String result) {
                        JSONObject json = JSONObject.parseObject(result);
                        if (json.get("code") != null && json.getInteger("code") == 0) {
                            JSONObject data = json.getJSONObject("data");
                            JSONArray bills = (JSONArray) data.get("bills");
                            String billIds = null;
                            for (int i = 0; i < bills.size(); i++) {
                                JSONObject bill = (JSONObject) bills.get(i);
                                if (billIds == null) {
                                    billIds = bill.getString("bill_id");
                                } else {
                                    billIds = billIds + "," + bill.getString("bill_id");
                                }
                            }
                            if (RedisUtil.set(ZzdConstant.ZZD_VALIDBILL_IDS + zzdAccount.getPassword(), billIds, ZzdConstant.ZZD_SESSION_VALIDIDTY+10*60)) {
                                log.debug("********** ZZD 查询有效订单成功！");
                                //再重新发起请求
                                request(finalUrl, paramsMap,zzdAccount,successCallBack, failedCallBack);

                            }
                        }
                    }
                }, new ApiCallBack() {
                    @Override
                    public void onResult(String result) {
                        log.error("！！！！！！！！！！ ZZD 查询有效订单失败！");
                        //再重新发起请求
                        request(finalUrl, paramsMap,zzdAccount,successCallBack, failedCallBack);
                    }
                }
        );
    }
    /**
     * sha1加密
     * @param input
     * @return
     */
    public static String sha1(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(input.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * hmacSha1加密
     * @param key
     * @param message
     * @return
     */
    public static String hmacSha1(String key,String message) {
        try {
            SecretKey Key = new SecretKeySpec(key.getBytes(),"HmacSHA1");  //创建密钥
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(Key); //初始化密钥
            mac.update(message.getBytes());
            byte[] res =mac.doFinal();  //进行HmacSHA1加密
            return bytesToHex(res);
        } catch (Exception e) {

        }
        return null;
    }
    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = HEX_ARRAY[v >>> 4];
            hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

    /**
     * 生成Result 对象
     * @param resutStr
     * @return
     */
    public static Result genResult(String resutStr){
        JSONObject json = JSONObject.parseObject(resutStr);
        if (json.getInteger("code") != null){
            if (json.getInteger("code") ==0){
                return Result.ok(0,json.getString("msg"),json.getJSONObject("data"));
            }else{
                return Result.error(json.getInteger("code"),json.getString("msg"),json.getJSONObject("data"));
            }
        }else{
            return Result.error(-1,json.getString("msg"),json.getJSONObject("data"));
        }
    }
    /**
     * 回调类
     * @author Administrator
     *
     */
    public static interface ApiCallBack{
        public void onResult(String result);
    }


}
